package org.springframework.security.config.annotation.web.configurers;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

import java.util.List;

/**
 * @author Dillon
 * @date 2024/6/29
 * @slogan 致敬大师 致敬未来的你
 * @desc 抽象配置类，用于创建Url级别的过滤器  FilterSecurityInterceptor
 * @see org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer
 * @see org.springframework.security.config.annotation.web.configurers.UrlAuthorizationConfigurer
 */
@Deprecated
public abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>
		extends AbstractHttpConfigurer<C, H> {

	private Boolean filterSecurityInterceptorOncePerRequest;

	/**
	 * 记录决策器管理器
	 */
	private AccessDecisionManager accessDecisionManager;

	AbstractInterceptUrlConfigurer() {
	}

	/**
	 * 核心 配置 FilterSecurityInterceptor 过滤器
	 * @param http 构建对象
	 * @throws Exception
	 */
	@Override
	public void configure(H http) throws Exception {
		// 创建 FilterInvocationSecurityMetadataSource 如果创建失败，则认为没有配置权限拦截，自然不用创建对应的拦截器
		FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);
		if (metadataSource == null) {
			return;
		}
		// 创建过滤器
		FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(http, metadataSource,
				http.getSharedObject(AuthenticationManager.class));
		// 属性设置
		if (this.filterSecurityInterceptorOncePerRequest != null) {
			securityInterceptor.setObserveOncePerRequest(this.filterSecurityInterceptorOncePerRequest);
		}
		// 调用后置处理器
		securityInterceptor = postProcess(securityInterceptor);
		// 过滤器添加
		http.addFilter(securityInterceptor);
		// 将拦截器设置到共享对象中
		http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);
	}

	/**
	 * 创建 FilterInvocationSecurityMetadataSource 实现类
	 * UrlAuthorizationConfigurer 中 DefaultFilterInvocationSecurityMetadataSource
	 * @param http 构建对象
	 * @return FilterInvocationSecurityMetadataSource
	 */
	abstract FilterInvocationSecurityMetadataSource createMetadataSource(H http);

	/**
	 * 获取对应的决策器配置列表
	 * @param http httpSecurity
	 * @return 决策器列表
	 */
	abstract List<AccessDecisionVoter<?>> getDecisionVoters(H http);

	/**
	 * 创建默认的角色管理器 任一决策成功，则返回成功
	 * @param http httpSecurity
	 * @return AccessDecisionManager
	 */
	private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
		AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
		return postProcess(result);
	}

	/**
	 * 获取决策管理器配置
	 * UrlAuthorizationConfigurer 未配置 所有创建默认的决策管理器
	 * ExpressionUrlAuthorizationConfigurer 配置了，所有使用配置
	 * @param http
	 * @return
	 */
	private AccessDecisionManager getAccessDecisionManager(H http) {
		if (this.accessDecisionManager == null) {
			this.accessDecisionManager = createDefaultAccessDecisionManager(http);
		}
		return this.accessDecisionManager;
	}

	/**
	 * 创建过滤器并填充属性
	 * @param http httpSecurity
	 * @param metadataSource 权限过滤元数据 记录针对于不同请求走不同的权限校验
	 * @param authenticationManager 认证管理器
	 * @return 构建成功过滤器对象
	 * @throws Exception 构建异常
	 */
	private FilterSecurityInterceptor createFilterSecurityInterceptor(H http,
			FilterInvocationSecurityMetadataSource metadataSource, AuthenticationManager authenticationManager)
			throws Exception {
		FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
		// 设置安全校验元数据
		securityInterceptor.setSecurityMetadataSource(metadataSource);
		// 设置决策器
		securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));
		// 设置认证管理器
		securityInterceptor.setAuthenticationManager(authenticationManager);
		// 设置上下文实现类
		securityInterceptor.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
		// 后验校验
		securityInterceptor.afterPropertiesSet();
		return securityInterceptor;
	}

	/**
	 * 定义抽象的url注册器
	 * @param <R>
	 * @param <T>
	 */
	public abstract class AbstractInterceptUrlRegistry<R extends AbstractInterceptUrlRegistry<R, T>, T>
			extends AbstractConfigAttributeRequestMatcherRegistry<T> {

		AbstractInterceptUrlRegistry() {
		}

		/**
		 * Allows setting the {@link AccessDecisionManager}. If none is provided, a
		 * default {@link AccessDecisionManager} is created.
		 * @param accessDecisionManager the {@link AccessDecisionManager} to use
		 * @return the {@link AbstractInterceptUrlConfigurer} for further customization
		 */
		public R accessDecisionManager(AccessDecisionManager accessDecisionManager) {
			AbstractInterceptUrlConfigurer.this.accessDecisionManager = accessDecisionManager;
			return getSelf();
		}

		/**
		 * Allows setting if the {@link FilterSecurityInterceptor} should be only applied
		 * once per request (i.e. if the filter intercepts on a forward, should it be
		 * applied again).
		 * @param filterSecurityInterceptorOncePerRequest if the
		 * {@link FilterSecurityInterceptor} should be only applied once per request
		 * @return the {@link AbstractInterceptUrlConfigurer} for further customization
		 */
		public R filterSecurityInterceptorOncePerRequest(boolean filterSecurityInterceptorOncePerRequest) {
			AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest;
			return getSelf();
		}

		/**
		 * Returns a reference to the current object with a single suppression of the type
		 * @return a reference to the current object
		 */
		@SuppressWarnings("unchecked")
		private R getSelf() {
			return (R) this;
		}

	}

}
